import os
import sys
import re
import urllib
from datetime import datetime
import logging
import wsgiref.handlers

import webapp2
from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import db

import AppEnv
from base import RequestHandler
from base import Error
from base import Role
from base import Decorators
from models import Blog
from models import Post
from models import Comment
from models import Tag
from models import Theme
import json
import utils

# the blogid_re to get blogid from self.reqpath
blogid_re = re.compile(r'/ajax/(?P<blogid>\w+)(?P<blogpath>(/.*)*)')

class CheckBlogId(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        errmsg = ''
        while True:
            blogId = self.reqpath[len('/ajax/admin/checkblogid/'):]
            blogId = urllib.unquote_plus(blogId)

            cr = Blog.checkblogId(blogId)
            if not cr[0]:
                errmsg = cr[1]
                break
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'errmsg': '',
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class AddBlog(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def post(self):
        errmsg = ''
        while True:
            blogId = self.param('blogId')
            blogName = self.param('blogName')
            owner = self.param('owner')

            cr = Blog.checkAll(blogId = blogId,
                               blogName = blogName,
                               owner = owner)
            if not cr[0]:
                errmsg = "\n".join(cr[1])
                break
            blog = Blog.new_blog(owner = owner,
                                        blogId = blogId,
                                        blogName = blogName
                                        )
                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'blogId': blog.blogId,
                                   'blogName': blog.blogName,
                                   'adminLink': '%s/admin/%s' % (AppEnv.apppath, blog.blogId),
                                   'bloglink': '%s/%s' % (AppEnv.apppath, blog.blogId),
                                   'email': blog.owner.email(),
                                   'nickname': blog.owner.nickname(),
                                   'dellink': '%s/ajax/admin/delblog/%s' % (AppEnv.apppath, blog.blogId),
                                   'resetlink': '%s/ajax/admin/resetblog/%s' % (AppEnv.apppath, blog.blogId),
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class DeleteBlog(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        errmsg = ''
        while True:
            blogId = self.reqpath[len('/ajax/admin/delblog/'):]
            blogId = urllib.unquote_plus(blogId)
            blogId = urllib.unquote_plus(blogId)

            try:
                Blog.delete_blog(blogId)
            except Error.NoThisObjectError,e:
                errmsg = 'no this blog'
                break
            except Exception,e:
                errmsg = str(e)
                break
                                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
    def post(self):
        return self.get()

class DeleteTheme(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        errmsg = ''
        while True:
            name = self.reqpath[len('/ajax/admin/deltheme/'):]
            name = urllib.unquote_plus(name)

            try:
                Theme.delete_theme(name)
            except Error.NoThisObjectError,e:
                errmsg = 'no this theme'
                break
            except Exception,e:
                errmsg = str(e)
                break
                                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
    def post(self):
        return self.get()

class ResetBlog(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        errmsg = ''
        while True:
            blogId = self.reqpath[len('/ajax/admin/resetblog/'):]
            blogId = urllib.unquote_plus(blogId)
            blogId = urllib.unquote_plus(blogId)

            try:
                Blog.reset_blog(blogId)
            except Error.NoThisObjectError,e:
                errmsg = 'no this blog'
                break
            except Exception,e:
                errmsg = str(e)
                break
                                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
    def post(self):
        return self.get()


class GetAvailableTheme(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        tl = Theme.getAvailableThemes()
        s = ['<select name="name">']
        s.append('<option value=""></option>')
        for t in tl:
            s.append('<option value="%s">%s</option>' % (t,t))
        s.append('</select>')
        self.write('\n'.join(s))
        return

    def post(self):
        return self.get()
    
class AddTheme(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def post(self):
        errmsg = ''
        while True:
            name = self.param('name')

            cr = Theme.checkAll(
                               name = name)
            if not cr[0]:
                errmsg = "\n".join(cr[1])
                break
            try:
                theme = Theme.create(name = name,
                                            )
            except Error.Error,e:
                errmsg = str(e)
                break
                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'name': theme.name,
                                   'deletelink': '%s/ajax/admin/deltheme/%s' % (AppEnv.apppath, theme.name),
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class DeleteTheme(RequestHandler.AjaxRequestHandler):
    @Decorators.needRole(Role.Admin)
    def get(self):
        errmsg = ''
        while True:
            name = self.reqpath[len('/ajax/admin/deltheme/'):]
            name = urllib.unquote_plus(name)

            try:
                Theme.delete_theme(name)
            except Error.NoThisObjectError,e:
                errmsg = 'no this theme'
                break
            except Exception,e:
                errmsg = str(e)
                break
                                          
            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
    def post(self):
        return self.get()

class AddComment(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.GUser)
    def post(self):
        errmsg = ''
        while True:
            user = users.get_current_user()
            
            uid = self.blogpath[len('/comment/'):]
            uid = utils.urlString2uid(uid)

            posts = Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
            if not posts:
                errmsg = 'no this post'
                break
            
            post = posts[0]
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = Comment.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break

            comment = Comment.add_comment(post, user, title, content)
            
            break

        if not errmsg:
            #succeed
            if self.is_blogowner:
                email = user.email()
            else:
                email = ''
            self.write(json.dumps({
                                   'status': True,
                                   'title': utils.toPageString(comment.title),
                                   'email': email,
                                   'nickname': user.nickname(),
                                   'is_blogowner': self.is_blogowner,
                                   'date': comment.date.strftime('%Y-%m-%d %H:%M'),
                                   'content': utils.toPageString(comment.content),
                                   'id': comment.key().id(),
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
            
class DeleteComment(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.Blogowner)
    def get(self):
        errmsg = ''
        while True:
            user = users.get_current_user()
        
            cid = int(self.blogpath[len('/delcomment/'):])

            try:
                Comment.delete_comment(cid = cid)
            except Error.PageNotFoundError,e:
                errmsg = 'no this comment'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({'status':True,}))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
            
class DeletePost(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.Blogowner)
    def get(self):
        errmsg = ''
        while True:
            uid = self.blogpath[len('/del/'):]
            uid = utils.urlString2uid(uid)

            try:
                Post.delete_post(uid = uid)
            except Error.PageNotFoundError,e:
                errmsg = 'no this post'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({'status':True,}))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class PublishPost(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.Blogowner)
    def get(self):
        errmsg = ''
        while True:
            uid = self.blogpath[len('/publish/'):]
            uid = utils.urlString2uid(uid)

            try:
                post = Post.publish_post(self.blog, uid = uid)
            except Error.PageNotFoundError,e:
                errmsg = 'no this post'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'uid': post.uid,
                                   'commentcount': post.comment_count(),
                                   'published': post.published,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class UnPublishPost(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.Blogowner)
    def get(self):
        errmsg = ''
        while True:
            uid = self.blogpath[len('/unpublish/'):]
            uid = utils.urlString2uid(uid)

            try:
                post = Post.publish_post(self.blog, uid = uid, publish=False)
            except Error.PageNotFoundError,e:
                errmsg = 'no this post'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'uid': post.uid,
                                   'commentcount': post.comment_count(),
                                   'published': post.published,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class GetTrackbackURL(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    def get(self):
        errmsg = ''
        while True:
            uid = self.blogpath[len('/track/'):]
            uid = utils.urlString2uid(uid)

            try:
                posts = Post.Post.all().filter('blog = ', self.blog).filter('published = ',True).filter('uid = ',uid).fetch(limit=1)
                if not posts:
                    errmsg = 'no this post'
                    break

                post = posts[0]
            except Error.PageNotFoundError,e:
                errmsg = 'no this post'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'uid': post.uid,
                                   'TrackbackURL': '%s%s/%s/track/%s'%(self.appconfig.HostURL, self.apppath, self.blogid, post.uid),
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return

class EditPost(RequestHandler.AjaxRequestHandler):
    @Decorators.blogRequest(blogid_re)
    @Decorators.needRole(Role.Blogowner)
    def post(self):
        errmsg = ''
        while True:
            #references
            rfcount = int(self.param('referencecount'))
            rfs = []
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    rfs.append(url)
            references = []
            flag = False
            for i in range(rfcount):
                url = self.param('reference%d'%i)
                if url:                    
                    if not (url.startswith('http:') or url.startswith('https://')):
                        url = 'http://' + url
                    try:
                        references.append(db.Link(url))
                    except db.BadValueError,e:
                        errmsg = 'Reference "%s" is not a valid URL' % url
                        flag = True
                        break
            if flag:
                break
            #uid
            uid = self.param('uid')
                
            #title
            title = self.param('title')
            title = utils.stripUnsafeTag(title)
            cr = Post.checkTitle(title)
            if not cr[0]:
                errmsg = cr[1]
                break
            #content
            content = self.param('content')
            content = utils.stripUnsafeTag(content)
            cr = Post.checkContent(content)
            if not cr[0]:
                errmsg = cr[1]
                break
            #published
            published = self.param('published') == '1'
            #tags
            tags = Tag.split_tags(utils.stripUnsafeTag(self.param('tags')))

            try:
                if not uid:
                    #new
                    newflag = True
                    uid = Post.new_post(blog=self.blog,
                                        title=title,
                                        content=content,
                                        tags=tags,
                                        references=references,
                                        publish = published)

                else:
                    #edit
                    newflag = False
                    Post.edit_post(blog=self.blog,
                                   uid = uid,
                                   title=title,
                                   content=content,
                                   tags=tags,
                                   references=references,
                                   publish=published)
            except Error.PageNotFoundError,e:
                errmsg = 'no this post'
                break

            break

        if not errmsg:
            #succeed
            self.write(json.dumps({
                                   'status': True,
                                   'uid': uid,
                                   'newflag': newflag,
                                   'published': published,
                                   }))
        else:
            #failed
            self.write(json.dumps({'status':False,'errmsg':errmsg}))

        return
    
app = webapp2.WSGIApplication([
    (AppEnv.apppath + '/ajax/admin/checkblogid/.*', CheckBlogId ),
    (AppEnv.apppath + '/ajax/admin/addblog', AddBlog ),
    (AppEnv.apppath + '/ajax/admin/delblog/.+', DeleteBlog ),
    (AppEnv.apppath + '/ajax/admin/resetblog/.+', ResetBlog ),
    (AppEnv.apppath + '/ajax/admin/getavailabletheme', GetAvailableTheme ),
    (AppEnv.apppath + '/ajax/admin/addtheme', AddTheme ),
    (AppEnv.apppath + '/ajax/admin/deltheme/.+', DeleteTheme ),
    (AppEnv.apppath + '/ajax/\w+/comment/.+', AddComment),
    (AppEnv.apppath + '/ajax/\w+/delcomment/.+', DeleteComment),
    (AppEnv.apppath + '/ajax/\w+/del/.+', DeletePost),
    (AppEnv.apppath + '/ajax/\w+/publish/.+', PublishPost),
    (AppEnv.apppath + '/ajax/\w+/unpublish/.+', UnPublishPost),
    (AppEnv.apppath + '/ajax/\w+/track/.+', GetTrackbackURL),
    (AppEnv.apppath + '/ajax/\w+/edit', EditPost),
    ('.*', RequestHandler.HTTP404),
], debug=AppEnv.debug)
